#include "playimage.h"
#include <QVBoxLayout>
#include <QMouseEvent>
#include <QPainter> // 用于绘制纯黑背景
#include <QDebug>

extern "C" {
#include "libavcodec/avcodec.h"
#include "libavutil/imgutils.h" // for av_image_alloc etc.
}

// --- GLWidget 实现 ---

// 静态成员初始化
const GLfloat GLWidget::vertices[] = {
    // positions        // texture coords
    1.0f,  1.0f, 0.0f, 1.0f, 1.0f, // top right
    1.0f, -1.0f, 0.0f, 1.0f, 0.0f, // bottom right
    -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, // bottom left
    -1.0f,  1.0f, 0.0f, 0.0f, 1.0f  // top left
};
const GLuint GLWidget::indices[] = {
    0, 1, 3, // first triangle
    1, 2, 3  // second triangle
};


GLWidget::GLWidget(QWidget* parent) : QOpenGLWidget(parent)
{
    m_size = QSize(0,0); // 初始尺寸为0
    // 如果需要在GLWidget构造时就显示黑色背景，可以在这里设置
    // setAutoFillBackground(true);
    // QPalette pal = palette();
    // pal.setColor(QPalette::Window, Qt::black);
    // setPalette(pal);
}

GLWidget::~GLWidget()
{
    // 确保在正确的上下文中清理 OpenGL 资源
    if (!isValid()) return;
    makeCurrent();
    if (m_texY) { m_texY->destroy(); delete m_texY; }
    if (m_texU) { m_texU->destroy(); delete m_texU; }
    if (m_texV) { m_texV->destroy(); delete m_texV; }
    if (m_program) { delete m_program; } // 删除 program
    glDeleteBuffers(1, &VBO);
    glDeleteBuffers(1, &EBO);
    glDeleteVertexArrays(1, &VAO);
    doneCurrent();
}

void GLWidget::repaint(AVFrame* frame)
{
    if (!isValid()) return; // 确保 OpenGL 上下文有效
    makeCurrent(); // 切换到当前上下文

    if (!frame || frame->width <= 0 || frame->height <= 0) {
        // 如果没有帧数据，可以选择清空或保持上一帧
        // 这里我们不主动清空，如果需要显示黑色，由 PlayImage 控制
        doneCurrent();
        return;
    }

    // 检查分辨率是否变化
    if (frame->width != m_size.width() || frame->height != m_size.height()) {
        if (m_texY) { m_texY->destroy(); delete m_texY; m_texY = nullptr; }
        if (m_texU) { m_texU->destroy(); delete m_texU; m_texU = nullptr; }
        if (m_texV) { m_texV->destroy(); delete m_texV; m_texV = nullptr; }

        QSize oldSize = m_size; // 保存旧尺寸
        m_size.setWidth(frame->width);
        m_size.setHeight(frame->height);

        // --- 修改开始: 发出尺寸变化信号 ---
        if (m_size != oldSize) {
            emit videoSizeChanged(m_size); // 发出信号
        }
        // --- 修改结束 ---

        // 重新计算渲染区域并更新
        resizeGL(width(), height());
    }

    // 创建纹理（如果需要）
    if (!m_texY) {
        m_texY = new QOpenGLTexture(QOpenGLTexture::Target2D);
        m_texU = new QOpenGLTexture(QOpenGLTexture::Target2D);
        m_texV = new QOpenGLTexture(QOpenGLTexture::Target2D);

        m_texY->setSize(frame->width, frame->height);
        m_texU->setSize(frame->width / 2, frame->height / 2); // YUV420
        m_texV->setSize(frame->width / 2, frame->height / 2); // YUV420

        m_texY->setMinMagFilters(QOpenGLTexture::Linear, QOpenGLTexture::Linear);
        m_texU->setMinMagFilters(QOpenGLTexture::Linear, QOpenGLTexture::Linear);
        m_texV->setMinMagFilters(QOpenGLTexture::Linear, QOpenGLTexture::Linear);

        m_texY->setFormat(QOpenGLTexture::R8_UNorm);
        m_texU->setFormat(QOpenGLTexture::R8_UNorm);
        m_texV->setFormat(QOpenGLTexture::R8_UNorm);

        m_texY->allocateStorage(QOpenGLTexture::Red, QOpenGLTexture::UInt8);
        m_texU->allocateStorage(QOpenGLTexture::Red, QOpenGLTexture::UInt8);
        m_texV->allocateStorage(QOpenGLTexture::Red, QOpenGLTexture::UInt8);
    }

    // 更新纹理数据
    m_options.setImageHeight(frame->height); // For correct row stride with padding

    if (frame->linesize[0] > 0) {
        m_options.setRowLength(frame->linesize[0]);
        m_texY->setData(QOpenGLTexture::Red, QOpenGLTexture::UInt8, static_cast<const void*>(frame->data[0]), &m_options);
    }
    if (frame->linesize[1] > 0) {
        m_options.setRowLength(frame->linesize[1]);
        m_texU->setData(QOpenGLTexture::Red, QOpenGLTexture::UInt8, static_cast<const void*>(frame->data[1]), &m_options);
    }
    if (frame->linesize[2] > 0) {
        m_options.setRowLength(frame->linesize[2]);
        m_texV->setData(QOpenGLTexture::Red, QOpenGLTexture::UInt8, static_cast<const void*>(frame->data[2]), &m_options);
    }

    doneCurrent(); // 释放上下文
    update(); // 请求重绘 QOpenGLWidget
}

void GLWidget::initializeGL()
{
    initializeOpenGLFunctions();
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // 设置清屏颜色为黑色

    m_program = new QOpenGLShaderProgram(this);
    // 确保你的 .qrc 文件中有这两个 shader 文件，并且路径正确
    if (!m_program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/vertex.vsh")) {
        qCritical() << "Vertex shader compilation failed:" << m_program->log();
        return;
    }
    if (!m_program->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/fragment.fsh")) {
        qCritical() << "Fragment shader compilation failed:" << m_program->log();
        return;
    }
    if (!m_program->link()) {
        qCritical() << "Shader program linking failed:" << m_program->log();
        return;
    }

    m_program->bind();
    m_program->setUniformValue("tex_y", 0);
    m_program->setUniformValue("tex_u", 1);
    m_program->setUniformValue("tex_v", 2);
    m_program->release(); // 先释放

    glGenVertexArrays(1, &VAO);
    glBindVertexArray(VAO);

    glGenBuffers(1, &VBO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glGenBuffers(1, &EBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    // Vertex Positions
    GLint posAttr = m_program->attributeLocation("aPos");
    glEnableVertexAttribArray(posAttr);
    glVertexAttribPointer(posAttr, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void*)0);

    // Texture Coordinates
    GLint texCordAttr = m_program->attributeLocation("aTexCord");
    glEnableVertexAttribArray(texCordAttr);
    glVertexAttribPointer(texCordAttr, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void*)(3 * sizeof(GLfloat)));

    glBindVertexArray(0); // 解绑VAO
    glBindBuffer(GL_ARRAY_BUFFER, 0); // 解绑VBO
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // 解绑EBO
}

void GLWidget::resizeGL(int w, int h)
{
    if (m_size.width() <= 0 || m_size.height() <= 0 || w <= 0 || h <= 0) {
        m_renderRect = QRectF(0, 0, w, h); // 如果没有视频尺寸，则铺满
        glViewport(0, 0, w, h);
        return;
    }

    // 计算保持宽高比的渲染区域
    float widgetAspect = (float)w / h;
    float videoAspect = (float)m_size.width() / m_size.height();

    float renderWidth, renderHeight;
    float posX, posY;

    if (widgetAspect > videoAspect) { // Widget 比视频宽 -> 高度填满，宽度居中
        renderHeight = h;
        renderWidth = h * videoAspect;
        posX = (w - renderWidth) / 2.0f;
        posY = 0;
    } else { // Widget 比视频窄（或等宽） -> 宽度填满，高度居中
        renderWidth = w;
        renderHeight = w / videoAspect;
        posX = 0;
        posY = (h - renderHeight) / 2.0f;
    }

    m_renderRect = QRectF(posX, posY, renderWidth, renderHeight);
    glViewport(m_renderRect.x(), m_renderRect.y(), m_renderRect.width(), m_renderRect.height());
}

void GLWidget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT);

    if (!m_texY || !m_texU || !m_texV || !m_program || !m_program->isLinked()) {
        // 如果纹理或着色器未准备好，直接返回（背景已清为黑色）
        return;
    }

    m_program->bind();
    glActiveTexture(GL_TEXTURE0);
    m_texY->bind();
    glActiveTexture(GL_TEXTURE1);
    m_texU->bind();
    glActiveTexture(GL_TEXTURE2);
    m_texV->bind();

    glBindVertexArray(VAO);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
    glBindVertexArray(0);

    // 释放纹理单元绑定不是必须的，但好习惯
    glActiveTexture(GL_TEXTURE2);
    m_texV->release();
    glActiveTexture(GL_TEXTURE1);
    m_texU->release();
    glActiveTexture(GL_TEXTURE0);
    m_texY->release();

    m_program->release();
}


// --- PlayImage 实现 ---

PlayImage::PlayImage(QWidget* parent, Qt::WindowFlags f)
    : QWidget(parent, f), m_userId(-1), m_isBlack(false), m_aspectRatio(16.0f / 9.0f) // 初始化宽高比
{

    m_glWidget = new GLWidget(this); // GLWidget 作为 PlayImage 的子控件

    m_overlayLabel = new QLabel(this); // Label 作为 PlayImage 的子控件
    m_overlayLabel->setAlignment(Qt::AlignBottom | Qt::AlignLeft);
    m_overlayLabel->setStyleSheet(
        "QLabel {"
        "   background-color: rgba(100, 100, 100, 180);" // 浅灰透明背景
        "   color: white;"                              // 白字
        "   padding: 2px;"
        "   font-size: 10px;" // 调整字体大小
        "}"
        );
    m_overlayLabel->setText(""); // 初始为空
    m_overlayLabel->adjustSize(); // 根据内容调整大小，但会被布局覆盖

    // 使用布局将 GLWidget 和 QLabel 叠放
    // 注意：直接在 PlayImage (QWidget) 上设置布局
    QVBoxLayout *layout = new QVBoxLayout(this); // 在 PlayImage 上创建布局
    layout->setContentsMargins(0, 0, 0, 0); // 无边距
    layout->setSpacing(0);
    layout->addWidget(m_glWidget); // GLWidget 在底层

    // QLabel 需要手动放置在顶部，布局可能不会完美叠放覆盖层
    // 因此，我们不将 Label 添加到布局，而是手动调整其位置和大小
    // 确保 Label 在 GLWidget 之上
    m_overlayLabel->raise();

    // 初始设置 Label 不可见，有用户信息时再显示
    m_overlayLabel->setVisible(false);
    m_overlayLabel->setAttribute(Qt::WA_TransparentForMouseEvents); // 让鼠标事件穿透标签

    // 设置大小策略，水平优先，垂直使用 heightForWidth
    setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
    // 连接 GLWidget 的尺寸变化信号
    connect(m_glWidget, &GLWidget::videoSizeChanged, this, &PlayImage::onVideoSizeChanged);

    // 设置最小尺寸可能仍然有用，但宽高比更重要
    // setMinimumSize(120, 120 / m_aspectRatio); // 根据初始宽高比设置最小尺寸
}

PlayImage::~PlayImage()
{
    // m_glWidget 和 m_overlayLabel 会因为是 this 的子控件而被自动删除
}

int PlayImage::heightForWidth(int w) const
{
    if (m_aspectRatio > 0.01f) { // 防止除零
        // 计算基于当前宽度和存储的宽高比的高度
        int h = static_cast<int>(w / m_aspectRatio);
        qDebug() << "PlayImage (" << m_userId << ") heightForWidth(" << w << ") ->" << h << " (aspectRatio:" << m_aspectRatio << ")";
        return h;
    } else {
        // 如果没有有效的宽高比，返回一个默认值或基于宽度的值
        return w * 9 / 16; // 默认 16:9
    }
}

// sizeHint 提供一个默认/理想尺寸，也应考虑宽高比
QSize PlayImage::sizeHint() const
{
    // 提供一个合理的默认尺寸，例如宽度为 160
    int hintWidth = 160;
    return QSize(hintWidth, heightForWidth(hintWidth));
}


void PlayImage::onVideoSizeChanged(const QSize& newSize)
{
    if (newSize.height() > 0) {
        m_aspectRatio = static_cast<float>(newSize.width()) / newSize.height();
        qDebug() << "PlayImage (" << m_userId << ") aspect ratio updated to:" << m_aspectRatio;
        // 告知布局系统尺寸提示可能已改变
        updateGeometry();
    }
}

// --- 修改开始: 提取更新标签位置逻辑 ---
void PlayImage::updateLabelPosition()
{
    if (m_overlayLabel && m_overlayLabel->isVisible()) {
        m_overlayLabel->adjustSize(); // 根据文字调整大小
        int labelHeight = m_overlayLabel->height();
        int labelWidth = m_overlayLabel->width() + 4;
        // 确保标签在 PlayImage 控件的边界内
        int x = 2;
        int y = qMax(0, height() - labelHeight - 2); // 防止 Y 坐标为负
        int w = qMin(labelWidth, width() - 4); // 防止宽度超出
        int h = labelHeight;
        m_overlayLabel->setGeometry(x, y, w, h);
        m_overlayLabel->raise(); // 再次确保在最上层
        qDebug() << "PlayImage (" << m_userId << ") updateLabelPosition to:" << x << y << w << h << "in widget size" << width() << height();
    }
}
// --- 修改结束 ---


// 在窗口大小改变时，调整 Label 的位置
void PlayImage::resizeEvent(QResizeEvent *event)
{
    QWidget::resizeEvent(event);

    updateLabelPosition();
}


void PlayImage::repaint(AVFrame* frame)
{
    m_isBlack = (frame == nullptr); // 如果帧为空，标记为黑屏
    if (!m_isBlack) {
        m_glWidget->repaint(frame);
        m_glWidget->setVisible(true);
    } else {
        m_glWidget->setVisible(false); // 隐藏 GL 控件
        update(); // 请求重绘 PlayImage 自身以显示黑色背景
    }
}

// 绘制纯黑背景 (当没有视频帧时)
void PlayImage::paintEvent(QPaintEvent *event)
{
    if (m_isBlack) {
        QPainter painter(this);
        painter.fillRect(rect(), Qt::black);
    } else {
        // 如果不是黑屏，正常绘制子控件 (GLWidget)
        QWidget::paintEvent(event);
    }
}


void PlayImage::setUserInfo(int userId, const QString& userName)
{
    m_userId = userId;
    m_userName = userName;
    QString labelText = QString("%1 (%2)").arg(userName).arg(userId);
    m_overlayLabel->setText(labelText);

    if (!userName.isEmpty() || userId != -1) {
        m_overlayLabel->setVisible(true);

        updateLabelPosition();

    } else {
        m_overlayLabel->setVisible(false);
    }
}

int PlayImage::getUserId() const
{
    return m_userId;
}

QString PlayImage::getUserName() const
{
    return m_userName;
}

void PlayImage::setBlackBackground()
{
    repaint(nullptr); // 传递 nullptr 来表示黑屏
}


void PlayImage::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton) {
        qDebug() << "PlayImage clicked, User ID:" << m_userId;
        emit clicked(m_userId); // 发出包含用户ID的信号
    }
    QWidget::mousePressEvent(event); // 调用基类事件处理
}
